package top.lixunda.ecommerce.server.user.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import top.lixunda.common.utils.ObjectValidators;
import top.lixunda.ecommerce.server.business.BaseServiceImpl;
import top.lixunda.ecommerce.server.business.api.entity.BusinessConstants;
import top.lixunda.ecommerce.server.business.api.entity.cache.CacheAdminUser;
import top.lixunda.ecommerce.server.user.api.entity.db.SystemMenuAllotDO;
import top.lixunda.ecommerce.server.user.api.entity.db.SystemMenuDO;
import top.lixunda.ecommerce.server.user.api.entity.dto.SystemMenuChangeDTO;
import top.lixunda.ecommerce.server.user.api.entity.dto.SystemMenuInsertDTO;
import top.lixunda.ecommerce.server.user.mapper.SystemMenuMapper;
import top.lixunda.ecommerce.server.user.service.IPermissionService;
import top.lixunda.ecommerce.server.user.service.ISystemMenuAllotService;
import top.lixunda.ecommerce.server.user.service.ISystemMenuService;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 系统菜单目录表，暂时由管理员进行配置 服务类
 *
 * @author lixunda
 * @version time:2020/4/23 17:06
 */
@Service
public class SystemMenuServiceImpl extends BaseServiceImpl<SystemMenuMapper, SystemMenuDO>
        implements ISystemMenuService {

    private final IPermissionService permissionService;

    private final ISystemMenuAllotService menuAllotService;

    @Autowired
    public SystemMenuServiceImpl(IPermissionService permissionService,
                                 ISystemMenuAllotService menuAllotService) {
        this.permissionService = permissionService;
        this.menuAllotService = menuAllotService;
    }

    /**
     * 添加多个菜单目录
     *
     * @param list 新添加的菜单目录数据列表
     * @return 是否添加成功
     */
    @Override
    public boolean insertMenu(List<SystemMenuInsertDTO> list) {
        if (ObjectValidators.isEmpty(list)) {
            throw getAppException("添加菜单失败！参数不能为空！");
        }
        CacheAdminUser cacheAdminUser = currentAdminUserCacheNotNull();
        LocalDateTime localDateTime = LocalDateTime.now();
        List<SystemMenuDO> insert = list.stream()
                .map(item -> {
                    SystemMenuDO systemMenuDO = new SystemMenuDO();
                    BeanUtils.copyProperties(item, systemMenuDO);
                    systemMenuDO
                            .setCreateUserId(cacheAdminUser.getAccount())
                            .setCreateUserName(cacheAdminUser.getName())
                            .setCreateUserType(cacheAdminUser.getType())
                            .setCreateTime(localDateTime)
                            .setCreateTime(localDateTime);
                    return systemMenuDO;
                })
                .collect(Collectors.toList());
        // 插入菜单数据
        boolean success = this.saveBatch(insert);
        if (!success) {
            throw getAppException("添加菜单失败！插入数据失败！");
        }
        // 插入菜单权限数据
        permissionService.insertAutoMenuPermission(insert);
        return true;
    }

    /**
     * 更新多个菜单目录
     *
     * @param list 需要更新的菜单目录数据列表
     * @return 是否更新成功
     */
    @Override
    public boolean updateMenuById(List<SystemMenuChangeDTO> list) {
        if (ObjectValidators.isEmpty(list)) {
            throw getAppException("更新菜单失败！参数不能为空！");
        }
        List<SystemMenuDO> insert = list.stream()
                .map(item -> {
                    SystemMenuDO systemMenuDO = new SystemMenuDO();
                    BeanUtils.copyProperties(item, systemMenuDO);
                    return systemMenuDO;
                })
                .collect(Collectors.toList());
        return this.updateBatchById(insert);
    }

    /**
     * 根据id删除菜单目录，删除包括子节点的所有节点
     *
     * @param id 菜单目录id
     * @return 是否删除成功
     */
    @Override
    public boolean removeMenuAllById(Integer id) {
        if (ObjectValidators.isEmpty(id)) {
            throw getAppException("删除菜单失败！菜单编号不能为空！");
        }
        SystemMenuDO systemMenuDO = this.queryById(id);
        if (ObjectValidators.isEmpty(systemMenuDO)) {
            throw getAppException("删除菜单失败！菜单不存在！");
        }
        List<SystemMenuDO> list = new ArrayList<>(32);
        list.add(systemMenuDO);
        List<Integer> parentIdList = Collections.singletonList(systemMenuDO.getMenuId());
        while (ObjectValidators.isNotEmpty(parentIdList)) {
            List<SystemMenuDO> temp = this.list(new LambdaQueryWrapper<SystemMenuDO>()
                    .in(SystemMenuDO::getParentMenuId, parentIdList));
            if (ObjectValidators.isNotEmpty(temp)) {
                list.addAll(temp);
                parentIdList = temp.stream()
                        .map(SystemMenuDO::getMenuId)
                        .collect(Collectors.toList());
            }
        }
        CacheAdminUser cacheAdminUser = currentAdminUserCacheNotNull();
        LocalDateTime localDateTime = LocalDateTime.now();
        // 移除菜单数据
        list.forEach(item -> item.setRemoveTime(localDateTime)
                .setRemoveUserId(cacheAdminUser.getAccount())
                .setRemoveUserName(cacheAdminUser.getName())
                .setRemoveUserType(cacheAdminUser.getType())
                .setUsable(BusinessConstants.USEABLE_FALSE));
        // 移除菜单数据
        boolean success = this.updateBatchById(list);
        if (!success) {
            throw getAppException("删除菜单失败！修改数据失败！");
        }
        // 移除菜单自动分配的菜单权限数据
        List<Integer> menuIds = list.stream()
                .map(SystemMenuDO::getMenuId)
                .collect(Collectors.toList());
        success = permissionService.removeAutoMenuPermission(menuIds);
        if (!success) {
            throw getAppException("删除菜单失败！移除菜单权限失败！");
        }
        // 移除菜单分配信息
        success = menuAllotService.update(new LambdaUpdateWrapper<SystemMenuAllotDO>()
                .set(SystemMenuAllotDO::getUsable, BusinessConstants.USEABLE_FALSE)
                .set(SystemMenuAllotDO::getRemoveTime, localDateTime)
                .set(SystemMenuAllotDO::getRemoveUserId, cacheAdminUser.getAccount())
                .set(SystemMenuAllotDO::getRemoveUserName, cacheAdminUser.getName())
                .set(SystemMenuAllotDO::getRemoveUserType, cacheAdminUser.getType())
                .in(SystemMenuAllotDO::getMenuId, menuIds)
                .eq(SystemMenuAllotDO::getUsable, BusinessConstants.USEABLE_TRUE));
        if (!success) {
            throw getAppException("删除菜单失败！移除菜单分配信息失败！");
        }
        return true;
    }

    /**
     * 根据id删除菜单目录，删除包括子节点的所有节点
     *
     * @param ids 菜单目录id
     * @return 是否删除成功
     */
    @Override
    public boolean removeMenuAllByIds(List<Integer> ids) {
        if (ObjectValidators.isEmpty(ids)) {
            throw getAppException("删除菜单失败！菜单编号不能为空！");
        }
        ids.forEach(item -> {
            if (!this.removeMenuAllById(item)) {
                throw getAppException("删除菜单失败！移除某个菜单项失败！");
            }
        });
        return true;
    }

    /**
     * 根据id获取菜单目录数据
     *
     * @param id 菜单目录id
     * @return 单条菜单目录数据
     */
    @Override
    public SystemMenuDO queryById(Integer id) {
        if (ObjectValidators.isEmpty(id)) {
            throw getAppException("查询菜单失败！菜单编号不能为空！");
        }
        return this.getById(id);
    }

    /**
     * 查询所有菜单目录信息
     *
     * @return 所有菜单目录信息
     */
    @Override
    public List<SystemMenuDO> queryAll() {
        return this.list();
    }

    /**
     * 根据菜单编码查询某一个子系统的菜单目录
     *
     * @param menuCode 菜单编码，唯一索引
     * @return 该子系统的菜单目录信息
     */
    @Override
    public List<SystemMenuDO> queryOneRootAllByCode(String menuCode) {
        if (ObjectValidators.isEmpty(menuCode)) {
            throw getAppException("查询菜单失败！菜单编码不能为空！");
        }
        SystemMenuDO systemMenuDO = this.getOne(new LambdaQueryWrapper<SystemMenuDO>()
                .eq(SystemMenuDO::getMenuCode, menuCode), false);
        if (ObjectValidators.isEmpty(systemMenuDO)) {
            throw getAppException("查询菜单失败！菜单不存在！");
        }
        if (ObjectValidators.isEmpty(systemMenuDO.getParentMenuId()) || systemMenuDO.getParentMenuId() <= 0) {
            throw getAppException("查询菜单失败！菜单不是根节点菜单编号！");
        }
        List<SystemMenuDO> result = new ArrayList<>(32);
        result.add(systemMenuDO);
        List<Integer> parentIdList = Collections.singletonList(systemMenuDO.getMenuId());
        while (ObjectValidators.isNotEmpty(parentIdList)) {
            List<SystemMenuDO> temp = this.list(new LambdaQueryWrapper<SystemMenuDO>()
                    .in(SystemMenuDO::getParentMenuId, parentIdList));
            if (ObjectValidators.isEmpty(temp)) {
                result.addAll(temp);
                parentIdList = temp.stream()
                        .map(SystemMenuDO::getMenuId)
                        .collect(Collectors.toList());
            }
        }
        return result;
    }

    /**
     * 根据父节点id获取子类节点列表
     *
     * @param id 父节点id
     * @return 子节点列表
     */
    @Override
    public List<SystemMenuDO> queryChildrenByParentId(Integer id) {
        if (ObjectValidators.isEmpty(id)) {
            throw getAppException("查询子菜单失败！菜单编号不能为空！");
        }
        // id小于等于零时返回根节点列表
        if (id <= 0) {
            return queryRoots();
        }
        return this.list(
                new LambdaQueryWrapper<SystemMenuDO>()
                        .eq(SystemMenuDO::getParentMenuId, id));
    }

    /**
     * 查询首层节点，父节点为空或小于等于0
     *
     * @return 首层节点
     */
    @Override
    public List<SystemMenuDO> queryRoots() {
        return this.list(new LambdaQueryWrapper<SystemMenuDO>()
                .isNull(SystemMenuDO::getParentMenuId)
                .or().le(SystemMenuDO::getParentMenuId, 0));
    }
}
